package framework;

import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Rectangle;

import framework.movements.LinearMovement;
import framework.movements.Movement;

public class BasicEntity implements MoveableEntity, Drawable, HitBoxable, Updatable, Scalable  {
	
	public final static int GRAVITY_FACTOR = 3000;
	
	protected int x;
	
	protected int y;
	
	protected int width;
	
	protected int height;
	
	protected int xSpeed;
	
	protected int ySpeed;
	
	protected Movement move;
	
	private float scale;
	
	public BasicEntity() {
	    this(0, 0);
	}
	
	public BasicEntity(int x, int y) {
	    this(x, y, 20, 20);
	}
		
	public BasicEntity(int x, int y, int width, int height) {
	    this.x = x;
	    this.y = y;
	    this.width = width;
	    this.height = height;
	    this.xSpeed = this.ySpeed = 0;
	    this.move = new LinearMovement();
	    this.scale = 1;
	}
	
	public void init(GameContainer gc) {
		setScale(Util.getScale(gc));
	}
	
	/**
	 * Perform a move. The move will be executed instead of the regular 
	 * character movement.
	 * @param m the move to perform
	 */
	public void move(Movement m) {
		if (this.move != null) {
			this.move.interrupt();
		}
		this.move = m;
		this.move.trigger();
	}

	@Override
	public void draw(Graphics g) {
		g.fillRect(x, y, width, height);
		g.setColor(Color.green);
	}
	
	@Override
	public void draw(Graphics g, Color filter) {
		draw(g, null);
	}

	@Override
	public int getX() {
		return this.x;
	}

	@Override
	public int getY() {
		return this.y;
	}

	@Override
	public int getWidth() {
		return (int) (this.width * scale);
	}

	@Override
	public int getHeight() {
		return (int) (this.height * scale);
	}

	@Override
	public void setX(int x) {
		this.x = x;
	}

	@Override
	public void setY(int y) {
		this.y = y;		
	}

	@Override
	public void setWidth(int width) {
		this.width = width;
	}

	@Override
	public void setHeight(int height) {
		this.height = height;
	}

	@Override
	public int getXspeed() {
		return (int) (this.xSpeed * scale);
	}

	@Override
	public int getYspeed() {
		return (int) (this.ySpeed * scale);
	}

	@Override
	public void setXspeed(int x) {
		this.xSpeed = x;
	}

	@Override
	public void setYspeed(int y) {
		this.ySpeed = y;
	}
	
	public boolean isMoving() {
		return getYspeed() != 0 || getXspeed() != 0;
	}
	
	public boolean isJumping() {
		return getYspeed() != 0;
	}

	@Override
	public Rectangle getHitBox() {
		return new Rectangle(getX(), getY(), getWidth(), getHeight());
	}

	@Override
	public void update(GameContainer gc, int delta) {
		int stepX, stepY;
		if (move.isActive()) {
			move.update(gc, delta);
			stepX = move.getX();
			stepY = move.getY();
		} else {
			stepX = getStepXSpeed(delta);
			stepY = getStepYSpeed(delta);
		}
		setX(this.x += stepX);
		setY(this.y += stepY);
	}
	
	/**
	 * Converts pixels / second x speed into pixels / frame
	 * @return the x speed for this frame
	 */
	public int getStepXSpeed(int delta) {
		return getXspeed() * delta / 1000;
	}

	/**
	 * Converts pixels / second y speed into pixels / frame
	 * @return the y speed for this frame
	 */
	public int getStepYSpeed(int delta) {
		return getYspeed() * delta / 1000;
	}

	public Movement getMove() {
		return move;
	}

	public void setMove(Movement move) {
		this.move = move;
	}

	@Override
	public void setScale(float scale) {
		this.scale = scale;
	}

	@Override
	public float getScale() {
		return scale;
	}
}